import { useState, forwardRef, useImperativeHandle } from 'react'
import debounce from 'lodash/debounce'
import { Select, Form, Spin, Empty } from 'antd'

import request from '@/utils/request'

import type { SelectProps } from 'antd/es/select'
import type { FormItemProps } from 'antd/es/form'

export interface SearchSelectProps extends SelectProps {
  extraProps?: {
    url: string
    data?: Record<string, any>
    formatData?: (data: any) => { options: Options; total: number }
    searchPropName: string
  }
  formItemProps?: FormItemProps
  childProps?: SelectProps
}

export interface SearchSelectRef {
  setOptions: any
}

const SearchSelect = forwardRef<SearchSelectRef, SearchSelectProps>(
  ({ formItemProps = {}, childProps = {}, extraProps = {} }, ref) => {
    const { url, data = {}, formatData, searchPropName = 'text' } = extraProps
    const [options, setOptions] = useState<Options>([])
    const [loading, setLoading] = useState(false)
    const [total, setTotal] = useState(0)
    const [param, setParam] = useState({ page: 1, pageSize: 50 })

    useImperativeHandle(ref, () => ({
      setOptions: setOptions,
    }))

    const handleSearch = (newValue: any) => {
      queryOptions({ [searchPropName]: newValue, page: 1 })
    }

    const queryOptions = debounce(searchParam => {
      setLoading(true)
      const newParam = Object.assign(param, data, searchParam)

      request(url as any, { data: newParam })
        .then(res => {
          if (res.code === 0 && res.data) {
            const { options: newOptions = [], total } = formatData ? formatData(res.data) : res.data
            setOptions(newParam.page === 1 ? [...newOptions] : [...options, ...newOptions])
            setTotal(total)
            setParam(newParam)
          }
        })
        .finally(() => {
          setLoading(false)
        })
    }, 300)

    const scrollToEnd = (e: any) => {
      e.persist()
      // 判断滑动到底部
      const { scrollTop, scrollHeight, clientHeight } = e.target
      return scrollHeight - scrollTop === clientHeight
    }

    const handlePopupScroll = (e: any) => {
      if (scrollToEnd(e) && options.length < total) {
        queryOptions({ page: param.page + 1 })
      }
    }

    return (
      <Form.Item {...formItemProps}>
        <Select
          showSearch
          placeholder="输入搜索"
          defaultActiveFirstOption={false}
          showArrow={false}
          filterOption={false}
          onSearch={handleSearch}
          options={options}
          onPopupScroll={handlePopupScroll}
          notFoundContent={
            loading ? (
              <Spin size="small" />
            ) : (
              <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据" />
            )
          }
          {...childProps}
        />
      </Form.Item>
    )
  }
)

SearchSelect.displayName = 'SearchSelect'

export default SearchSelect
